[HVM] Make copy_{to,from}_guest work for HVM domains.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 3 Aug 2006 14:22:25 +0000 (15:22 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 3 Aug 2006 14:22:25 +0000 (15:22 +0100)
Signed-off-by: Steven Smith <ssmith@xensource.com>
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/platform.c
xen/include/asm-x86/guest_access.h
xen/include/asm-x86/hvm/guest_access.h [new file with mode: 0644]
xen/include/asm-x86/shadow.h

index 9dd0fee66f7e1fc38c2335ee7fabca7b0cfbc251..7b348e32dd6ab685de18604ce8fd1a3bd0708eb6 100644 (file)
@@ -254,7 +254,7 @@ int cpu_get_interrupt(struct vcpu *v, int *type)
 int
 hvm_copy(void *buf, unsigned long vaddr, int size, int dir)
 {
-    unsigned long gpa, mfn;
+    unsigned long mfn;
     char *addr;
     int count;
 
@@ -263,10 +263,9 @@ hvm_copy(void *buf, unsigned long vaddr, int size, int dir)
         if (count > size)
             count = size;
 
-        if (hvm_paging_enabled(current)) {
-            gpa = gva_to_gpa(vaddr);
-            mfn = get_mfn_from_gpfn(gpa >> PAGE_SHIFT);
-        } else
+        if (hvm_paging_enabled(current))
+            mfn = gva_to_mfn(vaddr);
+        else
             mfn = get_mfn_from_gpfn(vaddr >> PAGE_SHIFT);
         if (mfn == INVALID_MFN)
             return 0;
index 1b5c5966afcd1d72fc9a4bf16eb17a93880830aa..efe443a8a0d63eb36fb9b2691bb754ea96e0c348 100644 (file)
@@ -1034,6 +1034,20 @@ void handle_mmio(unsigned long va, unsigned long gpa)
     }
 }
 
+/* Note that copy_{to,from}_user_hvm don't set the A and D bits on
+   PTEs, and require the PTE to be writable even when they're only
+   trying to read from it.  The guest is expected to deal with
+   this. */
+unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len)
+{
+    return !hvm_copy((void *)from, (unsigned long)to, len, HVM_COPY_OUT);
+}
+
+unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len)
+{
+    return !hvm_copy(to, (unsigned long)from, len, HVM_COPY_IN);
+}
+
 /*
  * Local variables:
  * mode: C
index 7be0f3efe6301d5c9e65de386cae0a3fc2b781e6..7b88aad86bce9b0ceae781f82037f9aba9352c03 100644 (file)
@@ -8,6 +8,8 @@
 #define __ASM_X86_GUEST_ACCESS_H__
 
 #include <asm/uaccess.h>
+#include <asm/hvm/support.h>
+#include <asm/hvm/guest_access.h>
 
 /* Is the guest handle a NULL reference? */
 #define guest_handle_is_null(hnd)        ((hnd).p == NULL)
@@ -28,6 +30,8 @@
 #define copy_to_guest_offset(hnd, off, ptr, nr) ({      \
     const typeof(ptr) _x = (hnd).p;                     \
     const typeof(ptr) _y = (ptr);                       \
+    hvm_guest(current) ?                                \
+    copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) :  \
     copy_to_user(_x+(off), _y, sizeof(*_x)*(nr));       \
 })
 
@@ -38,6 +42,8 @@
 #define copy_from_guest_offset(ptr, hnd, off, nr) ({    \
     const typeof(ptr) _x = (hnd).p;                     \
     const typeof(ptr) _y = (ptr);                       \
+    hvm_guest(current) ?                                \
+    copy_from_user_hvm(_y, _x+(off), sizeof(*_x)*(nr)) :\
     copy_from_user(_y, _x+(off), sizeof(*_x)*(nr));     \
 })
 
@@ -45,6 +51,8 @@
 #define copy_field_to_guest(hnd, ptr, field) ({         \
     const typeof(&(ptr)->field) _x = &(hnd).p->field;   \
     const typeof(&(ptr)->field) _y = &(ptr)->field;     \
+    hvm_guest(current) ?                                \
+    copy_to_user_hvm(_x, _y, sizeof(*_x)) :             \
     copy_to_user(_x, _y, sizeof(*_x));                  \
 })
 
@@ -52,6 +60,8 @@
 #define copy_field_from_guest(ptr, hnd, field) ({       \
     const typeof(&(ptr)->field) _x = &(hnd).p->field;   \
     const typeof(&(ptr)->field) _y = &(ptr)->field;     \
+    hvm_guest(current) ?                                \
+    copy_from_user_hvm(_y, _x, sizeof(*_x)) :           \
     copy_from_user(_y, _x, sizeof(*_x));                \
 })
 
  * Allows use of faster __copy_* functions.
  */
 #define guest_handle_okay(hnd, nr)                      \
-    array_access_ok((hnd).p, (nr), sizeof(*(hnd).p))
+    (hvm_guest(current) || array_access_ok((hnd).p, (nr), sizeof(*(hnd).p)))
 
 #define __copy_to_guest_offset(hnd, off, ptr, nr) ({    \
     const typeof(ptr) _x = (hnd).p;                     \
     const typeof(ptr) _y = (ptr);                       \
+    hvm_guest(current) ?                                \
+    copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) :  \
     __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr));     \
 })
 
 #define __copy_from_guest_offset(ptr, hnd, off, nr) ({  \
     const typeof(ptr) _x = (hnd).p;                     \
     const typeof(ptr) _y = (ptr);                       \
+    hvm_guest(current) ?                                \
+    copy_from_user_hvm(_y, _x+(off),sizeof(*_x)*(nr)) : \
     __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr));   \
 })
 
 #define __copy_field_to_guest(hnd, ptr, field) ({       \
     const typeof(&(ptr)->field) _x = &(hnd).p->field;   \
     const typeof(&(ptr)->field) _y = &(ptr)->field;     \
+    hvm_guest(current) ?                                \
+    copy_to_user_hvm(_x, _y, sizeof(*_x)) :             \
     __copy_to_user(_x, _y, sizeof(*_x));                \
 })
 
 #define __copy_field_from_guest(ptr, hnd, field) ({     \
     const typeof(&(ptr)->field) _x = &(hnd).p->field;   \
     const typeof(&(ptr)->field) _y = &(ptr)->field;     \
+    hvm_guest(current) ?                                \
+    copy_from_user_hvm(_x, _y, sizeof(*_x)) :           \
     __copy_from_user(_y, _x, sizeof(*_x));              \
 })
 
diff --git a/xen/include/asm-x86/hvm/guest_access.h b/xen/include/asm-x86/hvm/guest_access.h
new file mode 100644 (file)
index 0000000..7a89e81
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_X86_HVM_GUEST_ACCESS_H__
+#define __ASM_X86_HVM_GUEST_ACCESS_H__
+
+unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len);
+unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len);
+
+#endif /* __ASM_X86_HVM_GUEST_ACCESS_H__ */
index 397d4beb6b825e39365555b4f1ee1a3a221cbc1e..f7d76af88ee5678d23de4d3b2124bd38b7b8da72 100644 (file)
@@ -1734,6 +1734,13 @@ static inline unsigned long gva_to_gpa(unsigned long gva)
     return l1e_get_paddr(gpte) + (gva & ~PAGE_MASK); 
 }
 #endif
+
+static inline unsigned long gva_to_mfn(unsigned long gva)
+{
+    unsigned long gpa = gva_to_gpa(gva);
+    return get_mfn_from_gpfn(gpa >> PAGE_SHIFT);
+}
+
 /************************************************************************/
 
 extern void __update_pagetables(struct vcpu *v);